package com.xinxuan.contentcenter.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.BeanUtils;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xinxuan.contentcenter.domain.MidUserShare;
import com.xinxuan.contentcenter.domain.RocketmqTransactionLog;
import com.xinxuan.contentcenter.domain.Share;
import com.xinxuan.contentcenter.dto.*;
import com.xinxuan.contentcenter.enums.AuditStatusEnum;
import com.xinxuan.contentcenter.exception.BusinessException;
import com.xinxuan.contentcenter.feignclient.UserCenterFeignClient;
import com.xinxuan.contentcenter.mapper.MidUserShareMapper;
import com.xinxuan.contentcenter.mapper.RocketmqTransactionLogMapper;
import com.xinxuan.contentcenter.mapper.ShareMapper;
import com.xinxuan.contentcenter.util.JwtOperator;

import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;

/**
 * @author xinsl
 * @date 2021/11/10
 */

@Slf4j
@Service
public class ShareService {

    @Resource
    private ShareMapper shareMapper;

    @Resource
    private RocketmqTransactionLogMapper rocketmqTransactionLogMapper;

    @Resource
    private UserCenterFeignClient userCenterFeignClient;
    // @Autowired
    // private TransactionListener transactionListener;
    @Resource
    private MidUserShareMapper midUserShareMapper;
    @Resource
    private Source source;

    @Resource
    private JwtOperator jwtOperator;

    public ShareDTO findById(Integer id) {
        // 获取分享详情
        Share share = this.shareMapper.selectByPrimaryKey(id);
        // 发布人id
        Integer userId = share.getUserId();
        // 4. 编程体验不统一
        UserDTO userDTO = this.userCenterFeignClient.findById(userId);

        ShareDTO shareDTO = new ShareDTO();
        // 消息的装配
        BeanUtils.copyProperties(share, shareDTO);
        shareDTO.setWxNickname(userDTO.getWxNickname());
        return shareDTO;
    }

    public Share auditById(Integer id, ShareAuditDTO auditDTO) throws Exception {
        Share share = shareMapper.selectByPrimaryKey(id);

        if (Objects.equals(null, share)) {
            // throw new SecurityException("用户无权访问！");
            throw new BusinessException("参数非法！该分享不存在");
        }
        if (!Objects.equals("NOT_YET", share.getAuditStatus())) {
            throw new BusinessException("参数非法！该分享已审核通过或者审核不通过");
        }
        auditByIdInDB(id, auditDTO);
        if (AuditStatusEnum.PASS.equals(auditDTO.getAuditStatusEnum())) {
            UUID uuid = UUID.randomUUID();

            UserAddBonusDTO userAddBonusDTO = UserAddBonusDTO.builder().userId(share.getUserId()).bonus(50).build();
            source.output()
                .send(MessageBuilder.withPayload(userAddBonusDTO)
                    .setHeader(RocketMQHeaders.TRANSACTION_ID, uuid.toString()).setHeader("shard_id", id.toString())
                    .setHeader("dto", JSON.toJSONString(auditDTO)).build());
            // producer.sendMessageInTransaction(msg, auditDTO);
        } else {
            auditByIdInDB(id, auditDTO);
        } ;
        // Shut down once the producer instance is not longer in use.
        share = shareMapper.selectByPrimaryKey(id);
        return share;
    }

    @Transactional(rollbackFor = Exception.class)
    public void auditByIdInDB(Integer id, ShareAuditDTO auditDTO) {
        Share share = Share.builder().id(id).auditStatus(auditDTO.getAuditStatusEnum().toString())
            .reason(auditDTO.getReason()).build();
        shareMapper.updateByPrimaryKeySelective(share);
    }

    @Transactional(rollbackFor = Exception.class)
    public void auditByIdWiithRocketMqLog(Integer id, ShareAuditDTO auditDTO, String transactionId) {
        auditByIdInDB(id, auditDTO);
        rocketmqTransactionLogMapper
            .insertSelective(RocketmqTransactionLog.builder().transactionId(transactionId).log("审核分享...").build());
    }

    public PageInfo<Share> q(String title, Integer pageNo, Integer pageSize, Integer userId) {
        // 启动分页 切入不分页sql 自动拼接分页sql
        PageHelper.startPage(pageNo, pageSize);
        // 不分页sql
        List<Share> shares = shareMapper.selectByParam(title);
        List<Share> sharesDealed;
        if (Objects.equals(null, userId)) {
            sharesDealed = shares.stream().peek(share -> {
                share.setDownloadUrl(null);
            }).collect(Collectors.toList());
        } else {
            sharesDealed = shares.stream().peek(share -> {
                MidUserShare midUserShare = midUserShareMapper
                    .selectOne(MidUserShare.builder().userId(share.getUserId()).shareId(share.getId()).build());
                if (Objects.equals(null, midUserShare)) {
                    share.setDownloadUrl(null);
                }
            }).collect(Collectors.toList());
        }

        return new PageInfo<Share>(sharesDealed);
    }

    public Share exchangeById(Integer id, HttpServletRequest request) {
        // 1.根据id查询share

        Object userId = request.getAttribute("id");
        Share share = shareMapper.selectByPrimaryKey(id);
        if (Objects.isNull(share)) {
            new BusinessException("该分享不存在");
        }
        MidUserShare midUserShare =
            midUserShareMapper.selectOne(MidUserShare.builder().shareId(id).userId((Integer)userId).build());
        if (!Objects.isNull(midUserShare)) {
            return share;
        }
        // 2根据当前登录用户id，查询积分是否自购

        UserDTO user = userCenterFeignClient.findById((Integer)userId);
        if (user.getBonus() < share.getPrice()) {
            new BusinessException("用户积分不足");
        }
        // 3扣减积分 并往mid_user_share里面插入一条数据
        userCenterFeignClient.addBonus(UserAddBonusDTO.builder().userId((Integer)userId).bonus(0 - share.getPrice())
            .description("兑换分享").event("BUY").build());
        midUserShareMapper.insert(MidUserShare.builder().userId((Integer)userId).shareId(id).build());
        return share;
    }

    public Share contribute(ShareRequestDTO shareRequestDTO, String token) {
        Claims claims = jwtOperator.getClaimsFromToken(token);
        Integer userId = (Integer)claims.get("id");
        Share build =
            Share.builder().userId(userId).title(shareRequestDTO.getTitle()).isOriginal(shareRequestDTO.getIsOriginal())
                .author(shareRequestDTO.getAuthor()).cover("xxx").summary(shareRequestDTO.getSummary())
                .price(shareRequestDTO.getPrice()).downloadUrl(shareRequestDTO.getDownloadUrl()).buyCount(0)
                .showFlag(true).auditStatus("NOT_YET").reason(null).build();
        shareMapper.insertSelective(build);
        return build;
    }

    public Share contributeUpd(String id, ShareRequestDTO shareRequestDTO, String token) {
        Claims claims = jwtOperator.getClaimsFromToken(token);
        Integer userId = (Integer)claims.get("id");
        Share build = Share.builder().id(Integer.parseInt(id)).userId(userId).title(shareRequestDTO.getTitle())
            .isOriginal(shareRequestDTO.getIsOriginal()).author(shareRequestDTO.getAuthor()).cover("xxx")
            .summary(shareRequestDTO.getSummary()).price(shareRequestDTO.getPrice())
            .downloadUrl(shareRequestDTO.getDownloadUrl()).buyCount(0).showFlag(true).auditStatus("NOT_YET")
            .reason(null).build();
        shareMapper.updateByPrimaryKeySelective(build);
        return build;
    }

    public List<Share> getShares(String token) {
        Claims claims = jwtOperator.getClaimsFromToken(token);
        Integer userId = (Integer)claims.get("id");
        List<MidUserShare> select = midUserShareMapper.select(MidUserShare.builder().userId(userId).build());
        List<Integer> shareIds = select.stream().map(item -> {
            Integer shareId = item.getShareId();
            return shareId;
        }).collect(Collectors.toList());
        List<Share> myShare = new ArrayList<>();
        for (Integer shareId : shareIds) {
            Share share = shareMapper.selectByPrimaryKey(shareId);
            myShare.add(share);
        }

        return myShare;
    }

    public List<Share> getcontributions(String token) {
        Claims claims = jwtOperator.getClaimsFromToken(token);
        Integer userId = (Integer)claims.get("id");
        List<Share> select = shareMapper.select(Share.builder().userId(userId).build());
        return select;
    }
}
